package com.yuntsg.ruiijn.controller.search;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.*;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.core.KnnSearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SimpleQuery;
import com.yuntsg.nnsfcp.common.utils.UserUtil;
import com.yuntsg.ruiijn.databse_search.entity.*;
import com.yuntsg.ruiijn.databse_search.service.*;
import com.yuntsg.ruiijn.paperana.service.MatchService;
import com.yuntsg.ruiijn.paperana.utils.esutils.EsServerEntity;
import common.bean.*;
import common.util.*;
import common.vo.*;
//import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

@Controller
@RequestMapping("manager/pub/api")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@SuppressWarnings("all")
@Slf4j
public class PubSearchController {


    @Resource
    UserUtil userUtil;

    private final FileDetailService fileDetailsService;

    private final FileDetailTxtService fileDetailTxtService;


    private final FileRecordsService fileRecordsService;

    private final FolderTypeService folderTypeService;


    private final SearchSelfService searchSelfService;

    private final BussService bussService;


    private final MinioUtil minioUtil;
    private final CutImageUtil cutImageUtil;

    private final ExtractUtil extractUtil;

    private final ImageComparison imageComparison;

    private final FeatureService featureService;
    @Value("${upload.tempPath}")
    public String tempPath;
    @Resource
    MatchService matchService;
    @Autowired
    private NacosUtil nacosUtil;

    public static void main(String[] args) {
        String decrypt = AesEncryptUtils.decrypt("OIKV5oT5JAt8CTiQJJe5aA==");
        Map<String, String> map = FullTextUtil.fetchPdfUrl(AesEncryptUtils.decrypt("OIKV5oT5JAt8CTiQJJe5aA=="), 0);
    }

    /**
     * 文档上传
     *
     * @param file
     * @param title
     * @param author
     * @param content
     * @return
     * @throws IOException
     */
    @PostMapping("upload")
    @ResponseBody
    public R upload(@RequestParam(required = false) MultipartFile file, @RequestParam("title") String title, @RequestParam("author") String author, @RequestParam("content") String content, @RequestParam("type") Integer type, @RequestParam("pmut") String pmut) throws IOException {
        //0 文本 1图片 2 文档
        String md5 = null;
        if (StrUtil.isEmpty(title)) {
            return R.error("必填项不能为空！");
        }

        if (null != file) {
            md5 = SecureUtil.md5(file.getInputStream());
            FileRecord one = fileRecordsService.getOne(Wrappers.<FileRecord>lambdaQuery().eq(FileRecord::getMd5, md5).eq(FileRecord::getUploadId, userUtil.getUid()).last("limit 1"));
            if (null != one) {
                throw new RRException("文件已存在请勿重复上传！！");
            }
        }

        if (type == 0) {
            String tempName = tempPath + RandomUtil.randomString(5) + ".txt";
            FileUtil.writeString(content, tempName, StandardCharsets.UTF_8);
            File temp = new File(tempName);
            md5 = SecureUtil.md5(temp);
            String path = minioUtil.upload(FileUtil.getInputStream(temp), userUtil.getUid(), DateUtil.today(), temp.getName(), Scenario.txt);
            FileRecord fileRecord = new FileRecord().setType(type).setAuthor(author).setTitle(title).setFilePath(path).setUploadId(userUtil.getUid()).setUploadTime(DateUtil.date().getTime()).setMd5(md5);
            fileRecordsService.saveOrUpdate(fileRecord);
            fileRecordsService.extractFiles(minioUtil.downloadIm(path), fileRecord.getId(), userUtil.getUid(), 0, tempName, 1);
            try {
                FileUtil.del(temp);
            } catch (Exception e) {
//                e.printStackTrace();
            }

        } else if (type == 1) {
            String path = minioUtil.upload(file.getInputStream(), userUtil.getUid(), DateUtil.today(), file.getOriginalFilename(), Scenario.view);
            FileRecord fileRecord = new FileRecord().setType(type).setAuthor(author).setTitle(title).setFilePath(path).setUploadId(userUtil.getUid()).setUploadTime(DateUtil.date().getTime()).setMd5(md5);
            fileRecordsService.saveOrUpdate(fileRecord);
            FileDetails fileDetails = new FileDetails().setTpye(2).setFId(fileRecord.getId()).setPath(fileRecord.getFilePath());
            fileDetailsService.saveOrUpdate(fileDetails);
            List<FileDetails> work = cutImageUtil.workNoUid(fileDetails.getPath(), fileDetails.getId(), fileDetails.getFId(), -1, userUtil.getUid());
            if (work == null || work.size() == 0) {
                throw new RRException("图片太小或拆分失败");
            }
            fileDetailsService.saveOrUpdateBatch(work);
            fileDetailsService.updateById(fileDetails.setSplitStatus(0));
        } else {
            String path = minioUtil.upload(file.getInputStream(), userUtil.getUid(), DateUtil.today(), file.getOriginalFilename(), Scenario.documentation);
            FileRecord fileRecord = new FileRecord().setType(type).setAuthor(author).setPmut(pmut).setTitle(title).setFilePath(path).setUploadId(userUtil.getUid()).setUploadTime(DateUtil.date().getTime()).setMd5(md5);
            fileRecordsService.saveOrUpdate(fileRecord);
            fileRecordsService.extractFiles(file.getInputStream(), fileRecord.getId(), userUtil.getUid(), file.getOriginalFilename().toLowerCase().endsWith("pdf") ? 2 : 1, "", 1);
        }

        return R.ok();
    }

    //    @ApiOperation(value = "自定义多文本上传对比")
    @PostMapping("upload-mul")
    @ResponseBody
    public R uploadMul(@RequestParam(required = true) MultipartFile file1, @RequestParam(required = true) MultipartFile file2, @RequestParam("title") String title, @RequestParam("author") String author, @RequestParam("content") String content) throws IOException {

        // file1 默认原始文档 file2 待比对文档
        if (null == file1 || file2 == null) {
            throw new RRException("文件都必须提交！！");
        }
        String path = minioUtil.upload(file1.getInputStream(), userUtil.getUid(), DateUtil.today(), file1.getOriginalFilename(), Scenario.documentation);
        String md5 = SecureUtil.md5(file1.getInputStream());
        //默认拿第一个
        MultipartFile fileParamNew = file1;
        FileRecord fileRecord = new FileRecord().setType(3).setAuthor(author).setPmut("").setTitle(title).setFilePath(path).setUploadId(userUtil.getUid()).setUploadTime(DateUtil.date().getTime()).setMd5(md5);
        fileRecordsService.saveOrUpdate(fileRecord);
        fileRecordsService.extractFiles(fileParamNew.getInputStream(), fileRecord.getId(), userUtil.getUid(), fileParamNew.getOriginalFilename().toLowerCase().endsWith("pdf") ? 2 : 1, "", 2);
        //待比对的文件进行自定义es库
        List<FileDetailsTxt> pdf = fileRecordsService.extractFilesBackStr(file2.getInputStream(), fileRecord.getId(), userUtil.getUid(), file2.getOriginalFilename().toLowerCase().endsWith("pdf") ? 2 : 1, "");
        boolean b = matchService.dealManualData(pdf, fileRecord.getId(), userUtil.getUid());
        if (!b) {
            throw new RRException("文件入库异常");
        }
        return R.ok();
    }

    @RequestMapping("records")
    @ResponseBody
    public R records(@RequestParam("page") Integer page, @RequestParam("limit") Integer limit) {
        Page<FileRecord> temp = fileRecordsService.page(new Page<>(page, limit), Wrappers.<FileRecord>lambdaQuery().eq(FileRecord::getUploadId, userUtil.getUid()).orderByDesc(FileRecord::getId));
        return R.ok().put("list", temp.getRecords()).put("count", temp.getTotal());
    }

    @RequestMapping("delete_record")
    @ResponseBody
    public R deleteRecord(Integer id) {
        return R.ok().put("status", fileRecordsService.removeById(id) & fileDetailsService.removeByIds(SimpleQuery.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, id), FileDetails::getId)));
    }

    @RequestMapping("search_text_data")
    @ResponseBody
    public R searchTextData(@RequestParam("fid") Integer fid, @RequestParam("page") Integer page) {
        //纯文字处理
        Map<Integer, Long> group = SimpleQuery.group(Wrappers.<FileDetailsTxt>lambdaQuery().eq(FileDetailsTxt::getFId, fid).eq(FileDetailsTxt::getTpye, 1), FileDetailsTxt::getSegment, Collectors.counting());
        FileRecord byId = fileRecordsService.getById(fid);
        List<FileDetailsTxt> list = fileDetailTxtService.list(Wrappers.<FileDetailsTxt>lambdaQuery().eq(FileDetailsTxt::getFId, fid).eq(FileDetailsTxt::getTpye, 1).eq(FileDetailsTxt::getSegment, page));
        // 老板意思是动态拿 如果匹配到30% 以上整句标红色 且是全网比对时候 自定义暂时放掉
        if (byId.getType() != null && byId.getType() != 3) {
            for (FileDetailsTxt fileDetails : list) {
                String txtContent = fileDetails.getTxtContent();
                String matchContent = fileDetails.getMatchContent();
                if (StringUtil.isNull(matchContent)) {
                    boolean b = fileDetailsService.matchEsRes(txtContent, null);
                    if (b) {
                        String newtxtContent = "<em>" + txtContent + "</em>";
                        fileDetails.setMatchContent(newtxtContent);
                        fileDetailTxtService.updateById(fileDetails);
                    } else {
                        fileDetails.setMatchContent("<em></em>");
                        fileDetailTxtService.updateById(fileDetails);
                    }
                }
            }
        }
        return R.ok().put("type", byId.getType()).put("segment", page).put("total", group.size()).put("sentence", group.get(page)).put("data", list).put("words", list.stream().map(FileDetailsTxt::getTxtContent).collect(Collectors.summingInt(String::length)));
    }

    /**
     * 画词检索
     *
     * @param source  0 公共库 1 自建库
     * @param content
     * @return
     */
    @RequestMapping("search_text_str")
    @ResponseBody
    public R searchStr(@RequestParam("content") String content,
                       @RequestParam("source") Integer source,
                       @RequestParam("page") Integer page,
                       @RequestParam("type") Integer type,
                       @RequestParam("fid") Integer fid
    ) throws Exception {
        List<ReturnText> returnTexts = new ArrayList<>();
        if (type != null && type == 3) {
            // 自定义一对一对比 不参与全网
            Integer uid = userUtil.getUid();
            List<Hit<JSONObject>> hits = searchSelfService.mulpubParticiplesRetrieval(content, source, page, fid, uid);
            for (Hit<JSONObject> hit : hits) {
                Map<String, JsonData> data = hit.fields();
                String table_no = data.get("table_id").to(String[].class)[0];
                String table_id = data.get("file_id").to(String[].class)[0];
                String table_type = data.get("database_type").to(String[].class)[0];
                String subProject = data.get("sub_project").to(String[].class)[0];
                String sentence = data.get("sentence").to(String[].class)[0];
                String str = "";
                try {
                    str = data.get("str").to(String[].class)[0];
                } catch (Exception e) {

                }
                ReturnText returnText = new ReturnText();
                returnText.setTableNo(table_no);
                returnText.setTableId(table_id);
                returnText.setTableType(table_type);
                returnText.setSegment(subProject);
                returnText.setSentence(sentence);
                returnText.setScore("");
                returnText.setPre("");
                returnText.setTextContent(str);
                returnText.setPmid("");
                returnText.setNext("");
                if (StringUtil.isNotNull(str)) {
                    returnTexts.add(returnText);
                }

            }
        } else {
            List<EsServerEntity> hits = searchSelfService.pubParticiplesRetrieval(content, source, page);
            if (source == 0) {
                for (EsServerEntity hit : hits) {
//                    Map<String, JsonData> data = hit.getFields();
                    Map<String, String[]> data = hit.getFields();
                    String table_no = data.get("table_id")[0];
                    String table_id = data.get("file_id")[0];
                    String table_type = data.get("database_type")[0];
                    String subProject = data.get("sub_project")[0];
                    String sentence = data.get("sentence")[0];
                    // es 库存储的 1 是ncbi  2是wos
                    String tableMark = ("1".equals(table_type) ? "ncbi_pdf_to_txt_" : "wos_pdf_to_txt_") + table_no;
//                    log.info("// es 库存储 table_type 的 1 是ncbi  2是wos");
//                    log.info("table_type++" + table_type);

                    ReturnText returnText = new ReturnText();
                    returnText.setTableNo(table_no);
                    returnText.setTableId(table_id);
                    // 返回需要按照减一 也就是ncbi 是0 wos 是1
                    returnText.setTableType(Integer.parseInt(table_type) - 1 + "");
                    returnText.setSegment(subProject);
                    returnText.setSentence(sentence);
                    returnText.setScore(Double.toString(StfUtil.genScore(content, HtmlUtil.cleanHtmlTag(hit.getHighlight().get("str").get(0)))));
                    returnText.setPre(searchSelfService.fetchPreOrNext(table_type, Integer.parseInt(sentence) - 1, subProject, table_id, table_no));
                    returnText.setTextContent(hit.getHighlight().get("str").get(0));
//                    log.info("table_id++" + table_id);
//                    log.info("tableMark++" + tableMark);
                    if (table_type.equals("1")) {
                        try {
                            returnText.setPmid(AesEncryptUtils.encrypt(bussService.getPmid(tableMark, Integer.parseInt(table_id))));
                        } catch (Exception e) {

                        }

                    } else {
                        try {
                            returnText.setPmid(AesEncryptUtils.encrypt(bussService.getUtPmid(tableMark, Integer.parseInt(table_id))));

                        } catch (Exception e) {

                        }
                    }

                    returnText.setNext(searchSelfService.fetchPreOrNext(table_type, Integer.parseInt(sentence) + 1, subProject, table_id, table_no));
                    returnTexts.add(returnText);
                }
            } else {
                for (EsServerEntity hit : hits) {
//                    Map<String, JsonData> data = hit.getFields();
                    ReturnText returnText = new ReturnText();
//                    FileDetails fileDetails = fileDetailsService.getById(hit.id());
                    // 这个是什么id  后续再说 TODO GCR
                    FileDetails fileDetails = fileDetailsService.getById(hit.getESid());
                    if (null == fileDetails) {
                        continue;
                    }
                    returnText.setSegment(fileDetails.getSegment().toString());
                    returnText.setSentence(fileDetails.getSentence().toString());
                    returnText.setScore(hit.getScore().toString());
                    returnText.setPre(Optional.ofNullable(fileDetailsService.getOne(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, fileDetails.getFId()).eq(FileDetails::getSegment, fileDetails.getSegment()).eq(FileDetails::getSentence, fileDetails.getSentence() - 1))).orElse(new FileDetails().setTxtContent(" ")).getTxtContent());
                    returnText.setTextContent(hit.getHighlight().get("text").get(0));
                    returnText.setPmid(String.valueOf(fileDetails.getFId()));
                    returnText.setNext(Optional.ofNullable(fileDetailsService.getOne(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, fileDetails.getFId()).eq(FileDetails::getSegment, fileDetails.getSegment()).eq(FileDetails::getSentence, fileDetails.getSentence() + 1))).orElse(new FileDetails().setTxtContent(" ")).getTxtContent());
                    returnTexts.add(returnText);

                }
            }
        }


        return R.ok().put("data", returnTexts.stream().sorted(Comparator.comparing(ReturnText::getScore).reversed()).collect(Collectors.toList()));
    }

    /**
     * 图片列表
     *
     * @param fid
     * @return
     */
    @RequestMapping("img_list")
    @ResponseBody
    public R imgList(Integer fid) {
        FileRecord fileRecord = fileRecordsService.getById(fid);
        List<FileDetails> data2 = fileDetailsService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getTpye, 2).eq(FileDetails::getFId, fid).orderByAsc(FileDetails::getId)).stream().map(f -> f.setSubStatus(0)).collect(Collectors.toList());
        List<FileDetails> data3 = fileDetailsService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getTpye, 3).eq(FileDetails::getFId, fid).orderByAsc(FileDetails::getId)).stream().map(f -> f.setSubStatus(1)).collect(Collectors.toList());
        return R.ok().put("data_2", data2).put("data_3", data3).put("title", fileRecord.getTitle());
    }

    /**
     * 图片转移
     *
     * @param fid
     * @return/
     */
    @RequestMapping("removedelete")
    @ResponseBody
    public R removeDelete(@RequestParam(value = "ids") String[] ids, @RequestParam(value = "type") Integer type, @RequestParam(value = "rid") Integer rid) {
        List<FileDetails> fileDetailsList = fileDetailsService.listByIds(Arrays.asList(ids));
        fileDetailsService.saveOrUpdateBatch(fileDetailsList.stream().map(fileDetails -> fileDetails.setDeleteFlag(fileDetails.getDeleteFlag() == 0 ? -1 : 0)).collect(Collectors.toList()));
        return R.ok();
    }

    @RequestMapping("removedelete_step")
    @ResponseBody
    public R removeDelete(@RequestParam(value = "type") Integer type, @RequestParam(value = "rid") Integer rid) {

        List<FileDetails> orginList = fileDetailsService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getTpye, 2));

        List<Integer> dict = orginList.stream().map(FileDetails::getId).collect(Collectors.toList());

        List<FileDetails> data1 = fileDetailsService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getTpye, type).in(FileDetails::getFId, dict).eq(FileDetails::getDeleteFlag, 0));
        List<FileDetails> data2 = fileDetailsService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getTpye, type).in(FileDetails::getFId, dict).eq(FileDetails::getDeleteFlag, -1));
        List<List<FileDetails>> lists = Arrays.asList(data1, data2);
        return R.ok().put("data", lists);
    }

    /**
     * 图片拆分列表
     *
     * @param fid
     * @return type (1:文字 2:图片 3:用户上传 4 :拆分图片 5：拆分文字 6：用户手动拆分，7精细拆分）
     */
    @RequestMapping("splitting_list")
    @ResponseBody
    public R splittingList(@RequestParam("id") Integer id, @RequestParam("type") Integer type) {
        FileDetails main = fileDetailsService.getById(id);
        if (main.getTpye() == 2) {
            main.setSubStatus(0);
        } else {
            main.setSubStatus(1);
        }
        List<FileDetails> list = fileDetailsService.list(Wrappers.<FileDetails>lambdaQuery().select(FileDetails::getId, FileDetails::getPath, FileDetails::getCollectionStatus).eq(FileDetails::getTpye, type).eq(FileDetails::getFId, id));
        return R.ok().put("list", list).put("mian", main);
    }

    /**
     * 图片拆分功能
     * 报告
     *
     * @param fid
     * @param type 0普通拆分 1精细拆分
     * @return
     */
    @RequestMapping("imgSplitting")
    @ResponseBody
    public R imgSplitting(@RequestParam("id") Integer id, @RequestParam("type") Integer type) {
        FileDetails fileDetails = fileDetailsService.getById(id);
        Integer source = fileDetails.getTpye() == 2 ? -1 : -2;
        if (type == 0) {
            List<FileDetails> work = cutImageUtil.workNoUid(fileDetailsService.getById(id).getPath(), id, fileDetailsService.getById(id).getFId(), source, userUtil.getUid());
            if (work == null || work.size() == 0) {
                throw new RRException("图片太小或拆分失败");
            }
            fileDetailsService.saveOrUpdateBatch(work);
            fileDetailsService.updateById(new FileDetails().setId(id).setSplitStatus(0));
        } else {
            if (fileDetails.getSplitStatus() == 1) {
                throw new RRException("已经精细识图，请勿重复操作");
            }
            List<FileDetails> work = cutImageUtil.workfiligreeNoId(fileDetailsService.getById(id).getPath(), id, fileDetailsService.getById(id).getFId(), source, userUtil.getUid());
            if (work == null || work.size() == 0) {
                throw new RRException("图片太小或拆分失败");
            }
            fileDetailsService.saveOrUpdateBatch(work);
            fileDetailsService.updateById(new FileDetails().setId(id).setSplitStatus(1));
        }

        return R.ok("拆分完成");
    }

    /**
     * 图片点击检索
     *
     * @param source 0 全网检索 1 本文检索
     * @param file
     * @return
     * @throws IOException
     */
    @RequestMapping("search_image_id")
    @ResponseBody
    public R searchImageId(@RequestParam("id") Integer id,
                           @RequestParam("source") Integer source,
                           @RequestParam("page") Integer page,
                           @RequestParam("size") Integer size,
                           @RequestParam("step") Integer step,
                           @RequestParam(value = "rids", required = false) String[] rids) throws Exception {

        if (step == 1) {
            return R.ok("正在全网检索中，请稍后！");
        } else if (step == 2) {
            try {
                Thread.sleep(RandomUtil.randomInt(10, 20) * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return R.ok("全网检索完毕，正在入库,请稍后");
        } else if (step == 3) {
            try {
                Thread.sleep(RandomUtil.randomInt(10, 20) * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return R.ok("入库完毕，正在解析，请稍后");
        } else {
            Integer topk = 50;
            FileDetails fileDetails = fileDetailsService.getById(id);
            List<Float> floats = featureService.imageFeature(fileDetails.getPath());
            FileRecord record = fileRecordsService.getById(fileDetails.getRid());
            int total = 0;
            List<ReturnImage> returnImages = new ArrayList<>();
            record.setPmut(Optional.ofNullable(record.getPmut()).orElse("0"));
            FetchVectorVoStep fetchVectorVoStep;
            if (source == 2) {
                fetchVectorVoStep = searchSelfService.pubSearchImage(topk, floats.stream().map(Float::doubleValue).collect(Collectors.toList()), Arrays.asList(rids), record.getPmut());
            } else {
                fetchVectorVoStep = searchSelfService.pubSearchImage(topk, floats.stream().map(Float::doubleValue).collect(Collectors.toList()), source, record.getPmut());
            }
            total = fetchVectorVoStep.getTotal();
            if (total == 0) {
                throw new RRException("暂无相似图片");
            }
            PageUtil.setOneAsFirstPageNo();
            int start = PageUtil.getStart(page, size);
            int end = PageUtil.getEnd(page, size) > total ? total - 1 : PageUtil.getEnd(page, size);
            List<PubVectorImageRes> hits = fetchVectorVoStep.getData().subList(start, end);
            for (PubVectorImageRes hit : hits) {

                Integer table_no = hit.getTable_no();
                Integer serial_id = hit.getSerial_id();
                Integer top_x = hit.getTop_x();
                Integer top_y = hit.getTop_y();
                Integer bottom_x = hit.getBottom_x();
                Integer bottom_y = hit.getBottom_y();

//                String table_type = data.get("table_type").to(String[].class)[0];
                String tableMark = "ncbi_pdf_to_jpg_" + table_no;
                NcbiPdfToJpg imageData;
                try {
                    imageData = bussService.getImgData(serial_id, tableMark);
                } catch (Exception e) {
                    continue;
                }
                ReturnImage returnImage = new ReturnImage();
                returnImage.setTableNo(table_no);
                returnImage.setSerialId(serial_id);
                returnImage.setScore(hit.getScore());
                Image image = extractUtil.byteArrayToImage(imageData.getFigureZip());
                if (null == image) {
                    continue;
                }
                Image cut = ImgUtil.cut(extractUtil.byteArrayToImage(imageData.getFigureZip()), new Rectangle(top_x, top_y, bottom_x - top_x, bottom_y - top_y));
                returnImage.setImage(ImgUtil.toBytes(cut, ImgUtil.IMAGE_TYPE_JPG));
                returnImage.setType(2);
                returnImage.setTopX(top_x);
                returnImage.setTopY(top_y);
                returnImage.setBottomX(bottom_x);
                returnImage.setBottomY(bottom_y);
                returnImage.setImageName(imageData.getFileName());
                returnImage.setPmid(AesEncryptUtils.encrypt(imageData.getPmidUt()));
                returnImages.add(returnImage);
            }
            return R.ok().put("data", returnImages).put("total", total).put("oid", id);
        }
    }

    /**
     * 图片点击检索直接获取结果
     *
     * @param source 0 全网检索 1 本文检索
     * @param file
     * @return
     * @throws IOException
     */
    @RequestMapping("search_image_result")
    @ResponseBody
    public R searchImageResult(@RequestParam("id") Integer id, @RequestParam("level") Integer level, @RequestParam("source") Integer source, @RequestParam(value = "rids", required = false) String[] rids, HttpServletRequest request) throws Exception {
        String uid = userUtil.getUidStr();
        String contentsComparisonKey = IdUtil.fastSimpleUUID();
        new Thread(() -> {
            fileDetailsService.contentsComparisonLineSiginStep(id, source, Optional.ofNullable(rids).orElse(new String[]{}), uid, contentsComparisonKey, level, fileRecordsService.getById(fileDetailsService.getById(id).getRid()));
        }).start();
        return R.ok().put("contentsComparisonKey", contentsComparisonKey);
    }

    /**
     * 图片上传检索
     *
     * @param file
     * @param source 0 公共库 1 自建库
     * @return
     * @throws IOException
     */
    @RequestMapping("search_image_file")
    @ResponseBody
    public R searchImageFile(@RequestParam("file") MultipartFile file, @RequestParam("fid") Integer fid, @RequestParam("source") Integer source, @RequestParam("page") Integer page) throws IOException {
        Integer topk = 5;
        String docx = minioUtil.upload(file.getInputStream(), userUtil.getUid(), DateUtil.today(), file.getOriginalFilename(), Scenario.view);
        FileDetails fileDetails = new FileDetails().setRid(fid).setFId(fid).setTpye(3).setPath(docx);
        fileDetailsService.save(fileDetails);

        List<FileDetails> work = cutImageUtil.workNoUid(fileDetails.getPath(), fileDetails.getId(), fid, -2, userUtil.getUid());
        if (work == null || work.size() == 0) {
            throw new RRException("图片太小或拆分失败");
        }
        fileDetailsService.saveOrUpdateBatch(work);
        return R.ok();

    }

    /**
     * 图片转移到上传
     *
     * @param file
     * @param source 0
     * @return
     * @throws IOException
     */
    @PostMapping("move_image_file")
    @ResponseBody
    public R moveImageFile(@RequestBody MoveImageReq[] vo) throws IOException {
        FileDetails f = fileDetailsService.getById(vo[0].getOid());
        FolderType folderType = folderTypeService.getOne(Wrappers.<FolderType>lambdaQuery().eq(FolderType::getType, 1).eq(FolderType::getMainId, vo[0].getOid()).eq(FolderType::getRId, vo[0].getRid()).eq(FolderType::getUId, userUtil.getUid()));
        if (null == folderType) {
            FolderType folderTypeNew = new FolderType();
            folderTypeNew.setFolderName(f.getId().toString());
            folderTypeNew.setUId(userUtil.getUid());
            folderTypeNew.setRId(vo[0].getRid());
            folderTypeNew.setType(1);
            folderTypeNew.setMainId(vo[0].getOid());
            folderTypeService.save(folderTypeNew);
            folderType = folderTypeNew;
        }

        for (MoveImageReq moveImageReq : vo) {
            String tableMark = "ncbi_pdf_to_jpg_" + moveImageReq.getTableNo();
            NcbiPdfToJpg imageData = bussService.getImgData(moveImageReq.getSerialId(), tableMark);
            Integer fid;
            FileDetails one = fileDetailsService.getOne(Wrappers.<FileDetails>lambdaQuery()
                    .eq(FileDetails::getTpye, -1)
                    .eq(FileDetails::getTableNo, moveImageReq.getTableNo())
                    .eq(FileDetails::getSerialId, moveImageReq.getSerialId()).last("limit 1"));
            if (null == one) {
                String fileName = imageData.getFileName();
                String docx = minioUtil.upload(new ByteArrayInputStream(imageData.getFigureZip()), userUtil.getUid(), DateUtil.today(), fileName, Scenario.view);
                FileDetails fileDetails = new FileDetails().setTableNo(moveImageReq.getTableNo()).setSerialId(moveImageReq.getSerialId()).setTpye(-1).setPath(docx).setPmid(moveImageReq.getPmid());
                fileDetailsService.save(fileDetails);
                fid = fileDetails.getId();
            } else {
                fid = one.getId();
            }
            FileDetails fileDetails = new FileDetails();
            fileDetails.setFId(fid);
            fileDetails.setRid(moveImageReq.getRid());
            fileDetails.setTpye(7);
            fileDetails.setSplitStatus(1);
            fileDetails.setPmid(moveImageReq.getPmid());
            fileDetails.setCollectionStatus(folderType.getId());
            fileDetails.setDeleteFlag(0);
            Image image = extractUtil.byteArrayToImage(imageData.getFigureZip());
            if (null == image) {
                continue;
            }
            Image cut = ImgUtil.cut(image, new Rectangle(moveImageReq.getTopX(), moveImageReq.getTopY(), moveImageReq.getBottomX() - moveImageReq.getTopX(), moveImageReq.getBottomY() - moveImageReq.getTopY()));
            String docx = minioUtil.upload(ImgUtil.toStream(cut, ImgUtil.IMAGE_TYPE_JPG), userUtil.getUid(), DateUtil.today(), RandomUtil.randomString(5) + moveImageReq.getImageName(), Scenario.view);
            fileDetails.setPath(docx);
            fileDetails.setTopX(moveImageReq.getTopX());
            fileDetails.setTopY(moveImageReq.getTopY());
            fileDetails.setBottomX(moveImageReq.getBottomX());
            fileDetails.setBottomY(moveImageReq.getBottomY());
            fileDetailsService.save(fileDetails);
            List<Integer> listId = Optional.ofNullable(folderType.getListId()).orElse(new ArrayList<>());
            listId.add(fileDetails.getId());
            folderTypeService.saveOrUpdate(folderType.setListId(listId));
        }

        return R.ok();

    }

    @RequestMapping("heartbeat_detection")
    @ResponseBody
    public String heartbeatDetection() {
        return DateUtil.now();
    }

    @GetMapping("/status")
    @ResponseBody
    public R status() {
        return R.ok().put("data", true);
    }

    /**
     * 查看全文接口
     *
     * @param request
     * @param id
     * @return
     */
    @GetMapping("link_pub")
    @ResponseBody
    public R link(HttpServletRequest request, @RequestParam("pmid") String pmid, @RequestParam("type") Integer type) throws Exception {
        if (null == pmid) {
            return R.error("上传文章没有全文");
        }
        return R.ok().put("data", FullTextUtil.fetchPdfUrl(AesEncryptUtils.decrypt(pmid), type)).put("type", 1);
    }

    @PostMapping("fetchPmids")
    @ResponseBody
    public R fetchPmids(@RequestParam("file") MultipartFile file, @RequestParam("similarity") Integer similarity) throws IOException {
        if (null == similarity) {
            similarity = 80;
        }

        Integer topk = 5;
        String path = minioUtil.upload(file.getInputStream(), 99999999, DateUtil.today(), file.getOriginalFilename(), Scenario.view);

        List<FileDetails> work = cutImageUtil.workNoUid(path, -99, -99, 3, -999);
        List<String> pass = work.stream().filter(f -> f.getTpye().equals(4)).map(s -> s.getPath()).collect(Collectors.toList());
        pass.add(path);
        List<String> result = new ArrayList<>();
        for (String s : pass) {
            List<Float> floats = featureService.imageFeature(path);
            int total = 0;

            KnnSearchResponse<PubVectorImageFetchpmidRes> response = searchSelfService.fetchPmids(floats.stream().map(Float::doubleValue).collect(Collectors.toList()));
            total = response.hits().hits().size();
            if (total == 0) {
                throw new RRException("暂无相似图片");
            }

            for (Hit<PubVectorImageFetchpmidRes> hit : response.hits().hits()) {
                if (NumberUtil.isGreater(new BigDecimal(hit.score().toString()), new BigDecimal(NumberUtil.div(similarity.toString(), "100", 4).toString()))) {
                    PubVectorImageFetchpmidRes data = hit.source();
                    Integer table_no = data.getTable_no();
                    Integer serial_id = data.getSerial_id();


                    String tableMark = "ncbi_pdf_to_jpg_" + table_no;
                    NcbiPdfToJpg imageData;
                    try {
                        imageData = bussService.getImgData(serial_id, tableMark);
                    } catch (Exception e) {
                        continue;
                    }
                    result.add(imageData.getPmidUt());
                }
            }
        }

        return R.ok().put("data", result);
    }

//    /**
//     * 获取图片连线
//     *
//     * @param file
//     * @param similarity
//     * @return
//     * @throws IOException
//     */
//    @PostMapping("pictureWire")
//    @ResponseBody
//    public R pictureWire(@RequestBody PubSearchRequestVo requestVo) throws IOException {
//        String originalId = requestVo.getOriginalId();
//        FileDetails fileDetails = fileDetailsService.getById(originalId);
//        String[] split = fileDetails.getPath().split("/");
//        String sfileName = "";
//        if (requestVo.getType() == 0) {
//            Integer tableId = requestVo.getTableId();
//            Integer tableNo = requestVo.getTableNo();
//
//            String tableMark = "ncbi_pdf_to_jpg_" + tableNo;
//            NcbiPdfToJpg imageData = bussService.getImgData(tableId, tableMark);
//            byte[] figureZip = imageData.getFigureZip();
//
//            FileUtil.writeBytes(figureZip, tempPath + fileDetails.getPath().replace(split[split.length - 1], "") + "/" + imageData.getFileName());
//            sfileName = imageData.getFileName();
//        } else if (requestVo.getType() == 1) {
//            sfileName = split[split.length - 1];
//        } else {
//            String targetId = requestVo.getTargetId();
//            FileDetails targetFile = fileDetailsService.getById(targetId);
//            String[] targetSplit = targetFile.getPath().split("/");
//            sfileName = targetSplit[targetSplit.length - 1];
//
//        }
//
//        // /pic/2023-04-07/100389/0m2pel0nu385d.jpg
//
//        RequestVo vo = ConvertUtils.convertUnite(RequestVo.class, requestVo);
//        vo.setPath(LOCAL_FILE_PATH + fileDetails.getPath().replace(split[split.length - 1], ""));
//        vo.setSfilename(split[split.length - 1]);
//        vo.setDfilename(sfileName);
//        vo.setRfilename("result_" + split[split.length - 1]);
//        vo.setSsplittype(1);
//        vo.setDsplittype(1);
//
//        String json = HttpUtil.postJson("http://10.1.1.11:57979/comparison", vo);
//        JSONObject jsonObject = JSONObject.parseObject(json);
//        if (jsonObject.getString("code").equals("0")) {
//            JSONObject data = jsonObject.getJSONObject("data");
//            String path = data.getString("path");
//            String ssplitfilename = data.getString("ssplitfilename");
//            String dsplitfilename = data.getString("dsplitfilename");
//
//            List<Float> ssfloats = FeatureService.imageFeature(path + ssplitfilename);
//
//            List<Float> dsfloats = FeatureService.imageFeature(path + dsplitfilename);
//            float v = FeatureComparison.cosineSim(ArrayUtils.toPrimitive(ssfloats.toArray(new Float[0]), 0.0F), ArrayUtils.toPrimitive(dsfloats.toArray(new Float[0]), 0.0F));
//            data.put("similarityFeature", new BigDecimal(String.valueOf(v)).doubleValue());
//            return R.ok().put("data", data).put("req", vo);
//        } else {
//            return R.error(jsonObject.getString("msg"));
//        }
//    }

    /**
     * 图片手动切割
     *
     * @return
     * @throws IOException
     */
    @PostMapping("pictureManually")
    @ResponseBody
    public R pictureManually(@RequestBody PubSearchRequestVo requestVo) throws IOException {
        String originalId = requestVo.getOriginalId();
        FileDetails fileDetails = fileDetailsService.getById(originalId);


        Integer source = fileDetails.getTpye() == 2 ? -1 : -2;
        if (null != requestVo.getCoordinateList() && requestVo.getCoordinateList().size() > 0) {

            for (CoordinateVo coordinateVo : requestVo.getCoordinateList()) {
                Integer xTop = coordinateVo.getTopx();
                Integer yTop = coordinateVo.getTopy();
                Integer xBottom = coordinateVo.getBottomx();
                Integer yBottom = coordinateVo.getBottomy();
                String[] split = fileDetails.getPath().split("/");
                // 保存图片
                String path = fileDetails.getPath().replace(split[split.length - 1], "");
                Mat croppedImage = null;
                try {
//                    if (!FileUtil.exist(tempPath + path)) {
//                        FileUtil.mkdir(tempPath + path);
//                    }
                    Mat src = minioUtil.downloadMat(fileDetails.getPath());
                    croppedImage = new Mat(src, new Rect(xTop, yTop, (xBottom - xTop), (yBottom - yTop)));

                } catch (Exception e) {
                    return R.error("图片切割失败,请选择区域重试");
                }
                path += RandomUtil.randomString(6) + ".jpg";
                String docx = minioUtil.upload(minioUtil.coverInput(croppedImage), userUtil.getUid(), DateUtil.today(), path, Scenario.view);

                FileDetails fileDetailsS = new FileDetails();
                if (fileDetails.getCollectionStatus() == 0) {
                    fileDetailsS.setFId(fileDetails.getId());
                    fileDetailsS.setTpye(6);
                    fileDetailsS.setRid(Optional.ofNullable(fileDetails.getRid()).orElse(fileDetailsS.getFId()));
//                fileDetailsS.setCollectionStatus(source);
//                fileDetailsS.setSplitStatus(0);
                    fileDetailsS.setCollectionStatus(fileDetails.getCollectionStatus());
                    fileDetailsS.setSegment(0);
                    fileDetailsS.setStatus(0);
                    fileDetailsS.setPath(docx);
                    fileDetailsS.setTopX(xTop);
                    fileDetailsS.setTopY(yTop);
                    fileDetailsS.setBottomX(xBottom);
                    fileDetailsS.setBottomY(yBottom);
                } else {
                    fileDetailsS.setFId(fileDetails.getFId());
                    fileDetailsS.setTpye(6);
                    fileDetailsS.setRid(Optional.ofNullable(fileDetails.getRid()).orElse(fileDetailsS.getFId()));
//                fileDetailsS.setCollectionStatus(source);
//                fileDetailsS.setSplitStatus(0);
                    fileDetailsS.setCollectionStatus(fileDetails.getCollectionStatus());
                    fileDetailsS.setSegment(0);
                    fileDetailsS.setStatus(0);
                    fileDetailsS.setPath(docx);
                    fileDetailsS.setTopX(fileDetails.getTopX() + xTop);
                    fileDetailsS.setTopY(fileDetails.getTopY() + yTop);
                    fileDetailsS.setBottomX(fileDetails.getTopX() + xBottom);
                    fileDetailsS.setBottomY(fileDetails.getTopY() + yBottom);
                }

                fileDetailsService.saveOrUpdate(fileDetailsS);

            }


            if (fileDetails.getCollectionStatus() != 0) {
                fileDetailsService.removeById(fileDetails.getId());
                minioUtil.remove(fileDetails.getPath());
            }
        } else {
            return R.error("请选择区域");
        }
        return R.ok();
    }

    /**
     * 图片手动切割
     *
     * @return
     * @throws IOException
     */
    @PostMapping("pictureManually_pre")
    @ResponseBody
    public R pictureManuallyPre(@RequestBody PubSearchRequestVo requestVo) throws IOException {
        String originalId = requestVo.getOriginalId();
        FileDetails fileDetails = fileDetailsService.getById(originalId);

        if (null != requestVo.getCoordinateList() && requestVo.getCoordinateList().size() > 0) {
            CoordinateVo coordinateVo = requestVo.getCoordinateList().get(0);
            Integer xTop = coordinateVo.getTopx();
            Integer yTop = coordinateVo.getTopy();
            Integer xBottom = coordinateVo.getBottomx();
            Integer yBottom = coordinateVo.getBottomy();
            String[] split = fileDetails.getPath().split("/");

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImgUtil.cut(minioUtil.downloadIm(fileDetails.getPath()), out, new Rectangle(xTop, yTop, (xBottom - xTop), (yBottom - yTop)));

            return R.ok().put("data", out.toByteArray());
        }
        return R.error("获取失败");
    }


    /**
     * 提取图片
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("extractImages")
    @ResponseBody
    public R extractImages(@RequestParam(required = false) MultipartFile file, @RequestParam(required = false) Integer rid) throws IOException {
        String docx = minioUtil.upload(file.getInputStream(), userUtil.getUid(), DateUtil.today(), file.getOriginalFilename(), Scenario.documentation);
        fileRecordsService.extractPdf(file.getInputStream(), rid, userUtil.getUid(), docx);
        return R.ok();
    }

    /**
     * pdf 删除图片
     *
     * @param vo
     * @return
     */
    @GetMapping("/deleteImg")
    @ResponseBody
    public R deleteImg(@RequestParam("id") Integer id) throws IOException {
        return R.ok().put("status", fileDetailsService.removeById(id) & fileDetailsService.removeByIds(SimpleQuery.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, id), FileDetails::getId)));
    }


    /**
     * 文件转移
     */
    @GetMapping("/deleteImgBath")
    @ResponseBody
    public R folderdelete(@RequestParam(value = "ids[]") String[] ids) {
        for (String id : ids) {
            fileDetailsService.removeById(id);
            fileDetailsService.removeByIds(SimpleQuery.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, id), FileDetails::getId));
        }
        return R.ok();
    }

//    /**
//     * 添加进待选集合
//     *
//     * @param vo
//     * @return
//     */
//    @RequestMapping("/addSelectedCollection")
//    @ResponseBody
//    public R addSelectedCollection(@RequestParam(value = "ids[]") String[] ids) throws IOException {
//        return R.ok().put("status", fileDetailsService.saveOrUpdateBatch(fileDetailsService.listByIds(Arrays.asList(ids)).stream().map(f -> f.setCollectionStatus(1)).collect(Collectors.toList())));
//    }
//
//    /**
//     * 添加进目标集合
//     *
//     * @param vo
//     * @return
//     */
//    @RequestMapping("/addTargetCollection")
//    @ResponseBody
//    public R addTargetCollection(@RequestParam(value = "ids[]") String[] ids) throws IOException {
//        return R.ok().put("status", fileDetailsService.saveOrUpdateBatch(fileDetailsService.listByIds(Arrays.asList(ids)).stream().map(f -> f.setCollectionStatus(2)).collect(Collectors.toList())));
//    }

    /**
     * 集合列表
     *
     * @param vo
     * @return
     */
    @RequestMapping("/collectionList")
    @ResponseBody
    public R collectionList(@RequestParam("id") Integer id) throws IOException {
        List<Integer> list = SimpleQuery.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, id), FileDetails::getId);
        list.add(id);
        return R.ok().put("data_1", fileDetailsService.list(Wrappers.<FileDetails>lambdaQuery().in(FileDetails::getFId, list).eq(FileDetails::getCollectionStatus, 1))).put("data_2", fileDetailsService.list(Wrappers.<FileDetails>lambdaQuery().in(FileDetails::getFId, list).eq(FileDetails::getCollectionStatus, 2)));
    }


    /**
     * 图片自建对比
     *
     * @param vo
     * @return
     */
    @GetMapping("relatively")
    @ResponseBody
    public R relatively(@RequestParam("fid") Integer fid, @RequestParam("id") Integer id) throws IOException {

        Map<Integer, float[]> featureMap = fileDetailsService.imageFeatureWithIdForPub(fid);
        Map<Double, String> result = new HashMap<>();
        float[] feature = featureMap.get(id);
        for (Integer imgId : featureMap.keySet()) {
            if (imgId.equals(id)) {
                continue;
            }
            float v = FeatureComparison.cosineSim(feature, featureMap.get(imgId));
            result.put(new BigDecimal(String.valueOf(v)).doubleValue(), fileDetailsService.getById(imgId).getPath());
        }
        ;
        return R.ok().put("data", JSONUtil.parseObj(common.util.MapUtil.sortByKey(result, false)));
    }


//    public static void main(String[] args) throws Exception {
//        MinioClient client = MinioClient.builder().endpoint("minio.yuntsg.com").credentials("i2twmx", "qf3.1415").build();
//
//        String fileName = "anhuienoside c inhibits human ovaria source mol cell biochem so 2022 mar 29.pdf";
//
//        BufferedInputStream inputStream = FileUtil.getInputStream("D:\\Downloads\\anhuienoside c inhibits human ovaria source mol cell biochem so 2022 mar 29.pdf");
//
////        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
////                .bucket("ruijin")
////                .object(fileName)
////                // 上传时指定对应对ContentType
////                .contentType(ViewContentType.getContentType(fileName))
////                .stream(inputStream, inputStream.available(), -1)
////                .build();
////
////        ObjectWriteResponse objectWriteResponse = client.putObject(putObjectArgs);
//        GetPresignedObjectUrlArgs ruijin = GetPresignedObjectUrlArgs.builder()
//                .method(Method.GET)
//                .bucket("ruijin")
//                .object(fileName)
//                .build();
//
//        String presignedObjectUrl = client.getPresignedObjectUrl(ruijin);
//
//    }


}
